using System.Collections.Generic;
using System.Linq;

namespace System.IO
{
	/// <summary>
	/// 	Extension methods for the FileInfo and FileInfo-Array classes
	/// </summary>
	internal static class FileInfoExtensions
	{
		/// <summary>
		/// 	Changes the files extension.
		/// </summary>
		/// <param name = "file">The file.</param>
		/// <param name = "newExtension">The new extension.</param>
		/// <returns>The renamed file</returns>
		/// <example>
		/// 	<code>
		/// 		var file = new FileInfo(@"c:\test.txt");
		/// 		file.ChangeExtension("xml");
		/// 	</code>
		/// </example>
		public static FileInfo ChangeExtension(this FileInfo file, string newExtension)
		{
			newExtension = newExtension.EnsureStartsWith(".");
			string fileName = string.Concat(Path.GetFileNameWithoutExtension(file.FullName), newExtension);
			file.Rename(fileName);
			return file;
		}

		/// <summary>
		/// 	Renames a file.
		/// </summary>
		/// <param name = "file">The file.</param>
		/// <param name = "newName">The new name.</param>
		/// <returns>The renamed file</returns>
		/// <example>
		/// 	<code>
		/// 		var file = new FileInfo(@"c:\test.txt");
		/// 		file.Rename("test2.txt");
		/// 	</code>
		/// </example>
		public static FileInfo Rename(this FileInfo file, string newName)
		{
			string filePath = Path.Combine(Path.GetDirectoryName(file.FullName), newName);
			file.MoveTo(filePath);
			return file;
		}

		/// <summary>
		/// 	Renames a without changing its extension.
		/// </summary>
		/// <param name = "file">The file.</param>
		/// <param name = "newName">The new name.</param>
		/// <returns>The renamed file</returns>
		/// <example>
		/// 	<code>
		/// 		var file = new FileInfo(@"c:\test.txt");
		/// 		file.RenameFileWithoutExtension("test3");
		/// 	</code>
		/// </example>
		public static FileInfo RenameFileWithoutExtension(this FileInfo file, string newName)
		{
			string fileName = string.Concat(newName, file.Extension);
			file.Rename(fileName);
			return file;
		}
	}

	internal static class FileInfosExtensions
	{
		/// <summary>
		/// Appends file attributes for several files at once (additive to any existing attributes)
		/// </summary>
		/// <param name="files">The files.</param>
		/// <param name="attributes">The attributes to be set.</param>
		/// <returns>The changed files</returns>
		/// <remarks></remarks>
		public static IEnumerable<FileInfo> AddAttributes(this IEnumerable<FileInfo> files, FileAttributes attributes)
		{
			foreach (FileInfo fileInfo in files)
			{
				fileInfo.Attributes |= attributes;
				yield return fileInfo;
			}
		}

		/// <summary>
		/// Changes the extensions of several files at once.
		/// </summary>
		/// <param name="files">The files.</param>
		/// <param name="newExtension">The new extension.</param>
		/// <returns>The renamed files</returns>
		/// <remarks></remarks>
		public static IEnumerable<FileInfo> ChangeExtensions(this IEnumerable<FileInfo> files, string newExtension)
		{
			foreach (FileInfo fileInfo in files)
			{
				fileInfo.ChangeExtension(newExtension);
				yield return fileInfo;
			}
		}

		/// <summary>
		/// Copies several files to a new folder at once.
		/// </summary>
		/// <param name="files">The files.</param>
		/// <param name="targetPath">The target path.</param>
		/// <param name="overwrite">if set to <c>true</c> [overwrite].</param>
		/// <returns>The newly created file copies</returns>
		/// <remarks></remarks>
		public static IEnumerable<FileInfo> CopyTo(this IEnumerable<FileInfo> files, string targetPath, bool overwrite = true)
		{
			return from fileInfo in files
			       let fileName = Path.Combine(targetPath, fileInfo.Name)
			       select fileInfo.CopyTo(fileName, overwrite);
		}

		/// <summary>
		/// Deletes several files at once
		/// </summary>
		/// <param name="files">The files.</param>
		/// <remarks></remarks>
		public static void Delete(this IEnumerable<FileInfo> files)
		{
			foreach (FileInfo fileInfo in files)
			{
				fileInfo.Delete();
			}
		}

		/// <summary>
		/// Movies several files to a new folder at once and optionally consolidates any exceptions.
		/// </summary>
		/// <param name="files">The files.</param>
		/// <param name="targetPath">The target path.</param>
		/// <returns>The moved files</returns>
		/// <remarks></remarks>
		public static IEnumerable<FileInfo> MoveTo(this IEnumerable<FileInfo> files, string targetPath)
		{
			foreach (FileInfo file in files)
			{
				string fileName = Path.Combine(targetPath, file.Name);
				file.MoveTo(fileName);
				yield return file;
			}
		}

		/// <summary>
		/// Sets file attributes for several files at once
		/// </summary>
		/// <param name="files">The files.</param>
		/// <param name="attributes">The attributes to be set.</param>
		/// <returns>The changed files</returns>
		/// <remarks></remarks>
		public static IEnumerable<FileInfo> SetAttributes(this IEnumerable<FileInfo> files, FileAttributes attributes)
		{
			foreach (FileInfo fileInfo in files)
			{
				fileInfo.Attributes = attributes;
				yield return fileInfo;
			}
		}
	}
}